#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>
#include <string.h>
#define  NUM 1024
#define OPT_NUM 64
char lineCommand[NUM];
char *myargv[OPT_NUM]; //指针数组
int lastCode = 0;
int lastSig =0;
int main()
{
    while(1)
    {
        //1.输入提示符
        printf("用户名@主机名 当前路径# ");
        fflush(stdout);
        //2.获取用户输入的指令,输入的时候，我们会输入\n
        char *s = fgets(lineCommand,sizeof(lineCommand)-1,stdin);
        assert(s != NULL);
        (void)s;
        //当我输入ls回车的时候，实际读取了ls\n
        lineCommand[strlen(lineCommand)-1] = 0;  //清除最后一个\n
        // printf("%s\n",lineCommand);

        // "ls -a -l"  ->  "ls" "-a" "-l"
        // 字符串切割
        myargv[0] = strtok(lineCommand," ");
        //如果没有字串了，strtok返回NULL， myargv[end] = NULL 
        int i = 1;
        if(myargv[0] &&  strcmp(myargv[0],"ls") == 0) 
        {
            myargv[i++] = (char*)"--color=auto";
        }
        while(myargv[i++] =  strtok(NULL," "));
        //如果是cd命令，不需要创建子进程 ，让shell自己知心对应的命令，本质就是执行系统接口     
        //像这种不需要让我们子进程来执行，而是让shell自己执行的命令，我们叫做内建/内置命令
        if(myargv[0] != NULL && strcmp(myargv[0],"cd")== 0)
        {
            if(myargv[1] != NULL ) 
            {
                chdir(myargv[1]); 
                continue;
            }
        }
        //ehco $?
        if(myargv[0] != NULL && myargv[1] != NULL && strcmp(myargv[0],"echo") == 0) 
        {
            if(strcmp(myargv[1],"$?") == 0)
            {
                printf("%d, %d\n",lastCode,lastSig);
            }else
            {
                printf("%s\n",myargv[1]);
            }
            continue;
        }
        //测试是否成功 条件编译测试
#ifdef DEBUG 
        for(int i = 0; myargv[i]; ++i)
        {
             printf("myargv[%d]:%s\n",i,myargv[i]);
        }
#endif       
    //执行命令
    pid_t id = fork();
    assert(id != -1);
    if(id == 0)
    {
        execvp(myargv[0],myargv);
        exit(1);
    }
    int status = 0;
    pid_t ret =  waitpid(id, &status, 0);
    assert(ret > 0);
    (void)ret;
    lastCode = ((status >> 8)&0xFF);
    lastSig = (status & 0x7F);
    }
} 
